home *** CD-ROM | disk | FTP | other *** search
- /* $VER: pasm output_abs.c V0.4 (05.07.97)
- *
- * This file is part of pasm, a portable PowerPC assembler.
- * Copyright (c) 1997 Frank Wille
- *
- * pasm is freeware and part of the portable and retargetable ANSI C
- * compiler vbcc, copyright (c) 1995-97 by Volker Barthelmann.
- * pasm may be freely redistributed as long as no modifications are
- * made and nothing is charged for it. Non-commercial usage is allowed
- * without any restrictions.
- * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
- * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
- *
- *
- * v0.4 (05.07.97) phx
- * Absolute output format supports correct relocations and
- * aligments. The user will be warned, if external references
- * are present.
- * v0.2 (25.03.97) phx
- * Writes ELF object for 32-bit PowerPC big-endian. Either absolute
- * or ELF output format may be selected. ELF is default for all
- * currently supported platforms. PPCasm supports nine different
- * relocation types (there are much more...).
- * Compiles and works also under NetBSD/amiga (68k).
- * Changed function declaration to 'new style' in all sources
- * (to avoid problems with '...' for example).
- * v0.1 (11.03.97) phx
- * First test version with all PowerPC instructions and most
- * important directives. Only raw, absolute output.
- * v0.0 (04.03.97) phx
- * File created.
- */
-
-
- #define OUTPUT_ABS_C
- #include "ppcasm.h"
- #define BASEREG_OFFSET 0x7ffc /* @@@ ? */
-
-
- void output_absolute(struct GlobalVars *);
- static void wr_err(struct GlobalVars *);
-
-
-
- void output_absolute(struct GlobalVars *gv)
- {
- struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
- struct Reloc *nextrel,*rel;
- struct XReference *xref;
- unsigned long offs = gv->absbase;
- FILE *fp;
-
- /* calculate section base addresses */
- while (nextsec = (struct Section *)sec->n.next) {
- if (!(sec->flags & SF_DISCARD)) {
- sec->index = (uint32)offs;
- offs += (sec->size + 3) & ~3;
- }
- sec = nextsec;
- }
-
- /* create output file */
- sec = (struct Section *)gv->sectionlist.first;
- if (fp = fopen(gv->dest_name,"w")) {
- while (nextsec = (struct Section *)sec->n.next) {
- if (!(sec->flags & SF_DISCARD) && sec->size) {
-
- /* try to resolve relocations */
- rel = (struct Reloc *)sec->reloclist.first;
- while (nextrel = (struct Reloc *)rel->n.next) {
- uint32 *p = (uint32 *)((char *)sec->contents + rel->offset);
- uint32 a = rel->relocsect->index + rel->addend;
-
- switch (rel->type) {
- case R_PPC_ADDR32:
- *p = ECVW(a);
- break;
- case R_PPC_ADDR16:
- *(uint16 *)p = ECVH((uint16)a);
- break;
- case R_PPC_ADDR16_LO:
- *(uint16 *)p = ECVH((uint16)(a & 0xffff));
- break;
- case R_PPC_ADDR16_HA:
- if (a & 0x8000)
- a += 0x10000;
- case R_PPC_ADDR16_HI:
- *(uint16 *)p = ECVH((uint16)(a >> 16));
- break;
- case R_PPC_ADDR24:
- *p = ECVW((uint32)((*(uint8 *)p & 0xfc) << 24) |
- (a & 0x3fffffc) | (uint32)(*((uint8 *)p+3) & 3));
- break;
- case R_PPC_ADDR14:
- case R_PPC_ADDR14_BRTAKEN:
- case R_PPC_ADDR14_BRNTAKEN:
- *((uint16 *)p+1) = ECVH((uint16)(a & 0xfffc) |
- (uint16)(*((uint8 *)p+3) & 3));
- break;
- case R_PPC_REL24:
- *p = ECVW((uint32)((*(uint8 *)p & 0xfc) << 24) |
- ((a - (sec->index + rel->offset)) & 0x3fffffc) |
- (uint32)(*((uint8 *)p+3) & 3));
- break;
- case R_PPC_REL14:
- case R_PPC_REL14_BRTAKEN:
- case R_PPC_REL14_BRNTAKEN:
- *((uint16 *)p+1) = ECVH((uint16)((a - (sec->index +
- rel->offset - 2)) & 0xfffc) |
- (uint16)(*((uint8 *)p+3) & 3));
- break;
- case R_PPC_REL32:
- *p = ECVW(a - (sec->index + rel->offset));
- break;
- case R_PPC_TOC16:
- if (gv->tocsect)
- a -= gv->tocsect->index + BASEREG_OFFSET;
- else
- a -= BASEREG_OFFSET;
- *(uint16 *)p = ECVH((uint16)a);
- break;
- default:
- error(53,elfrel_name[rel->type & ELFRELNAMMSK],rel->offset,
- sec->name); /* relocation not supported */
- break;
- }
- rel = nextrel;
- }
-
- /* any external references? (would be difficult here :) */
- while (xref = (struct XReference *)remhead(&sec->xreflist))
- error(55,xref->xsymbol->name); /* no xrefs in absolute output */
-
- /* write section contents */
- if (sec->flags & SF_UNINITIALIZED) { /* bss section */
- unsigned long s = (sec->size + 3) >> 2;
- while (s--) {
- if (!fwrite(gv->alignment_bytes,1,4,fp))
- wr_err(gv);
- }
- }
- else {
- if (!fwrite(sec->contents,1,sec->size,fp))
- wr_err(gv);
- if ((4-(sec->size&3))&3) { /* aligment */
- if (!fwrite(gv->alignment_bytes,1,(4-(sec->size&3))&3,fp))
- wr_err(gv);
- }
- }
- }
- sec = nextsec;
- }
- fclose(fp);
- }
- else
- error(25,gv->dest_name); /* unable to create output file */
- }
-
-
- static void wr_err(struct GlobalVars *gv)
- {
- error(26,gv->dest_name); /* write error */
- }
-